/*
 * transaction.cpp
 *
 *  Created on: 03.03.2019
 *      Author: thomas
 */

#include <string.h>
#include <assert.h>
#include "iota/transaction.h"
#include "iota/addresses.h"
#include "aux.h"

Transaction::Transaction() {
	m_charTX = 0;
	init();
}

void Transaction::init() {
	if (m_charTX) {
		// wipe everything clean
		memset(m_charTX, '9', sizeof(TX_t));

		// set zero-terminator for convenience
		m_charTX->m_zeroterminator = 0;
	}
	// initialize int values
	m_addressIndex = (uint32_t) -1;
	m_value = 0;
	m_timestamp = 0;
	m_currentIndex = 0;
	m_lastIndex = 0;
	m_attachmentTimestamp = 0;
	m_attachmentTimestampLowerBound = 0;
	m_attachmentTimestampUpperBound = 0;
	m_prev = (Transaction*) 0;
	m_next = (Transaction*) 0;
	m_type = Transaction::Empty;
}

void Transaction::parse(char *tx) {
	memcpy(m_charTX, tx, sizeof(TX_t));
	Conversion conv;

	m_value = conv.chars_to_s64(m_charTX->m_value, sizeof(m_charTX->m_value));
	m_timestamp = (int32_t) conv.chars_to_s64(m_charTX->m_timestamp,
			sizeof(m_charTX->m_timestamp));
	m_currentIndex = (int32_t) conv.chars_to_s64(m_charTX->m_currentIndex,
			sizeof(m_charTX->m_currentIndex));
	m_lastIndex = (int32_t) conv.chars_to_s64(m_charTX->m_lastIndex,
			sizeof(m_charTX->m_lastIndex));
	m_attachmentTimestamp = conv.chars_to_s64(m_charTX->m_attachmentTimestamp,
			9);
	m_attachmentTimestampLowerBound = conv.chars_to_s64(
			m_charTX->m_attachmentTimestampLower, 9);
	m_attachmentTimestampUpperBound = conv.chars_to_s64(
			m_charTX->m_attachmentTimestampUpper, 9);

	if (m_value < 0) {
		setType(Transaction::Input);
	} else if (m_value > 0) {
		setType(Transaction::Output);
	} else {
		setType(Transaction::Empty);	// not yet known if signature
	}

}

void Transaction::convertIntValues() {
	Conversion conv;
	conv.s64_to_chars(m_value, m_charTX->m_value, sizeof(m_charTX->m_value));
	conv.u32_to_chars(m_timestamp, m_charTX->m_timestamp,
			sizeof(m_charTX->m_timestamp));
	conv.u32_to_chars(m_currentIndex, m_charTX->m_currentIndex,
			sizeof(m_charTX->m_currentIndex));
	conv.u32_to_chars(m_lastIndex, m_charTX->m_lastIndex,
			sizeof(m_charTX->m_lastIndex));
	// is set after PoW
	/*    int64_to_chars(m_attachmentTimestamp, m_charTX->m_attachmentTimestamp, 9);
	 int64_to_chars(m_attachmentTimestampLowerBound, m_charTX->m_attachmentTimestampLower, 9);
	 int64_to_chars(m_attachmentTimestampUpperBound, m_charTX->m_attachmentTimestampUpper, 9);*/
}

void Transaction::increment_obsolete_tag(unsigned int tag_increment) {
	char extended_tag[81];
	unsigned char tag_bytes[48];
	rpad_chars(extended_tag, m_charTX->m_obsoleteTag, NUM_HASH_TRYTES);

	Conversion conv;
	conv.chars_to_bytes(extended_tag, tag_bytes, NUM_HASH_TRYTES);

	conv.bytes_add_u32_mem(tag_bytes, tag_increment);
	conv.bytes_to_chars(tag_bytes, extended_tag, 48);

	memcpy(m_charTX->m_obsoleteTag, extended_tag, 27);
}

void Transaction::setMessage(const char *msg) {
	rpad_chars(m_charTX->m_signatureMessageFragment, msg,
			sizeof(m_charTX->m_signatureMessageFragment));
}
void Transaction::setAddress(const char *addr) {
	memcpy(m_charTX->m_address, addr, 81);
}

void Transaction::setAddressIndex(uint32_t idx) {
	m_addressIndex = idx;
}

void Transaction::setValue(int64_t value) {
	m_value = value;
}
void Transaction::setObsoleteTag(char *tag) {
	rpad_chars(m_charTX->m_obsoleteTag, tag, sizeof(m_charTX->m_obsoleteTag));
}
void Transaction::setTimestamp(uint32_t timestamp) {
	m_timestamp = timestamp;
}
void Transaction::setCurrentIndex(uint32_t index) {
	m_currentIndex = index;
}
void Transaction::setLastIndex(uint32_t index) {
	m_lastIndex = index;

}

void Transaction::setTag(const char *tag) {
	rpad_chars(m_charTX->m_tag, tag, 27);
}

// following after / during pow
void Transaction::setTrunkTransaction(const char *trunk) {
	rpad_chars(m_charTX->m_trunkTransaction, trunk,
			sizeof(m_charTX->m_trunkTransaction));
}
void Transaction::setBranchTransaction(const char *branch) {
	rpad_chars(m_charTX->m_branchTransaction, branch,
			sizeof(m_charTX->m_branchTransaction));
}

void Transaction::setAttachmentTimestamp(int64_t timestamp) {
	Conversion conv;
	conv.s64_to_chars(timestamp, m_charTX->m_attachmentTimestamp,
			sizeof(m_charTX->m_attachmentTimestamp));
}

void Transaction::setAttachmentTimestampLowerBound(int64_t timestamp) {
	Conversion conv;
	conv.s64_to_chars(timestamp, m_charTX->m_attachmentTimestampLower,
			sizeof(m_charTX->m_attachmentTimestampLower));
}
void Transaction::setAttachmentTimestampUpperBound(int64_t timestamp) {
	(void) timestamp;	// surpress unused
	memcpy(m_charTX->m_attachmentTimestampUpper, "K99999999",
			sizeof(m_charTX->m_attachmentTimestampUpper));
	// todo ... conversion gives wrong chars
	//conv->s64_to_chars(timestamp, m_charTX->m_attachmentTimestampUpper, sizeof(m_charTX->m_attachmentTimestampUpper));
}

void Transaction::setNonce(const char *nonce) {
	memcpy(m_charTX->m_nonce, nonce, sizeof(m_charTX->m_nonce));
}

void Transaction::setBundle(const char *bundle) {
	memcpy(m_charTX->m_bundle, bundle, sizeof(m_charTX->m_bundle));
}

// uses hashing - use it with care
void Transaction::getFullAddress(char* fullAddress) {
	uint8_t addressBytes[48];
	Conversion conv;
	conv.chars_to_bytes(m_charTX->m_address, addressBytes, 81);
	Address::getAddressWithChecksum(addressBytes, fullAddress);
}

#include "debugprintf.h"
void Transaction::calcBundleBytes() {
	Conversion conv;
	conv.chars_to_bytes(m_charTX->m_address, m_bundleBytes, 81);

	char bundleChars[81] = {0};
	char* p = bundleChars;

	convertIntValues();
	memcpy(p, m_charTX->m_value, 27); p+=27;
	memcpy(p, m_charTX->m_obsoleteTag, 27); p+=27;
	memcpy(p, m_charTX->m_timestamp, 9); p+= 9;
	memcpy(p, m_charTX->m_currentIndex, 9); p+= 9;
	memcpy(p, m_charTX->m_lastIndex, 9); p+= 9;

	// now we have exactly one chunk of 243 trits
	conv.chars_to_bytes(bundleChars, &m_bundleBytes[48], 81);

//	debugPrintHex(m_bundleBytes, 96, 48);
}


/*
 void Transaction::setTimestampChars(char* timestamp) {
 memcpy(m_charTX->m_timestamp, timestamp, 9);
 }

 void Transaction::setLastIndexChars(char* index) {
 memcpy(m_charTX->m_lastIndex, index, 9);
 }

 void Transaction::setValueChars(char* value) {
 memcpy(m_charTX->m_value, value, 27);
 }

 */
